package com.swedne.test.net;

import android.content.Context;
import android.net.LinkAddress;
import android.os.Build;
import android.util.Log;

import androidx.annotation.RequiresApi;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

public class NetUtils extends ReflectionFunctions {
    private static final String ClassName_EthernetManager = "android.net.EthernetManager";
    private static final String ClassName_StaticIpConfiguration = "android.net.StaticIpConfiguration";
    private static final String ClassName_IpConfiguration = "android.net.IpConfiguration";
    private Object IEthernetManager;

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public NetUtils(Context mContext, String ip, String gateWay, String subnetmask, String dns) {
        super(mContext);
        try {
            final Class<?> classEthernetManager = getClass(ClassName_EthernetManager);
            this.IEthernetManager = getSystemServiceInstance("ethernet");
            final Class<?> mStaticIpConfiguration = getClass(ClassName_StaticIpConfiguration);
            Object mStaticIpConfigurationInstance = mStaticIpConfiguration.newInstance();
            Inet4Address inetAddr = (Inet4Address) InetAddress.getByName(ip);
            InetAddress gatewayAddr = InetAddress.getByName(gateWay);
            InetAddress dnsAddr = InetAddress.getByName(dns);
            int prefixLength = maskStr2InetMask(subnetmask);
            if (inetAddr.getAddress().toString().isEmpty() || prefixLength == 0 || gatewayAddr.toString().isEmpty()
                    || dnsAddr.toString().isEmpty()) {
                return;
            }
            Class<?> clazz = null;
            try {
                clazz = Class.forName("android.net.LinkAddress");
            } catch (Exception e) {
                // TODO: handle exception
            }

            Class[] cl = new Class[]{InetAddress.class, int.class};
            Constructor cons = null;

            // 取得所有构造函数
            try {
                cons = clazz.getConstructor(cl);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }

            // 给传入参数赋初值
            Object[] x = {inetAddr, prefixLength};

            try {
                LinkAddress linkAddress = (LinkAddress) cons.newInstance(x);
                Field ipAddress = mStaticIpConfiguration.getDeclaredField("ipAddress");
                ipAddress.set(mStaticIpConfigurationInstance, linkAddress);
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }

            Class<?> ipConfiguration = Class.forName(ClassName_IpConfiguration);
//            String ipAssignment = Class.forName(ipConfiguration.getCanonicalName() + "$" + "IpAssignment").getDeclaredField("STATIC").get(null).toString();
//            String proxySettings = Class.forName(ipConfiguration.getCanonicalName() + "$" + "ProxySettings").getDeclaredField("NONE").get(null).toString();

            List<Object> allEnumIp = getAllEnum(ipConfiguration.getCanonicalName() + "$" + "IpAssignment");
            List<Object> allEnumProxy = getAllEnum(ipConfiguration.getCanonicalName() + "$" + "ProxySettings");

            Object ipConfigurationInstance = ipConfiguration.newInstance();
            Method setStaticIpConfiguration = getMethod(ipConfiguration, "setStaticIpConfiguration", mStaticIpConfiguration);
            Method setIpAssignment = getMethod(ipConfiguration, "setIpAssignment", allEnumIp.get(0).getClass());
            invokeMethod(setIpAssignment, ipConfigurationInstance, allEnumIp.get(0));
            Method setProxySettings = getMethod(ipConfiguration, "setProxySettings", allEnumProxy.get(0).getClass());
            invokeMethod(setProxySettings, ipConfigurationInstance, allEnumProxy.get(0));
            invokeMethod(setStaticIpConfiguration, ipConfigurationInstance, mStaticIpConfigurationInstance);
            Method setConfiguration = getMethod(classEthernetManager, "setConfiguration", String.class, ipConfiguration);
            invokeMethod(setConfiguration, IEthernetManager, "eth0", ipConfigurationInstance);
            Log.d("zrz", "success ip" + inetAddr.getHostAddress());

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (Exception exception) {


        }

    }

    /**
     * 根据枚举的字符串获取枚举的值
     *
     * @param className 包名+类名
     * @return
     * @throws Exception
     */
    public static List<Object> getAllEnum(String className) throws Exception {
        // 获得枚举类对象
        Class<Enum> clazz = (Class<Enum>) Class.forName(className);
        List<Object> list = new ArrayList<Object>();
        //获取全部枚举实例
        Enum[] enumConstants = clazz.getEnumConstants();
        Map<String, Object> map = null;
        for (Enum enum1 : enumConstants) {
            list.add(enum1);
        }
        return list;
    }


    public static int maskStr2InetMask(String maskStr) {
        StringBuffer sb;
        String str;
        int inetmask = 0;
        int count = 0;
        /*
         * check the subMask format
         */
        Pattern pattern = Pattern.compile(
                "(^((\\d|[01]?\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(\\d|[01]?\\d\\d|2[0-4]\\d|25[0-5])$)|^(\\d|[1-2]\\d|3[0-2])$");
        if (pattern.matcher(maskStr).matches() == false) {
            Log.e("zrz", "subMask is error");
            return 0;
        }

        String[] ipSegment = maskStr.split("\\.");
        for (int n = 0; n < ipSegment.length; n++) {
            sb = new StringBuffer(Integer.toBinaryString(Integer.parseInt(ipSegment[n])));
            str = sb.reverse().toString();
            count = 0;
            for (int i = 0; i < str.length(); i++) {
                i = str.indexOf("1", i);
                if (i == -1)
                    break;
                count++;
            }
            inetmask += count;
        }
        return inetmask;
    }
}
